#if !defined(MGPATTERN_H_INCLUDED)
#define MGPATTERN_H_INCLUDED

#pragma warning(push)

#include <yvals.h>

#pragma warning(disable: 4018)
#pragma warning(disable: 4100)
#pragma warning(disable: 4245)
#pragma warning(disable: 4663) 
#pragma warning(disable: 4702)
#pragma warning(disable: 4710)
#pragma warning(disable: 4786)

#include <vector>
#include <algorithm>
#include <locale>

#pragma warning(pop)

typedef std::basic_string<TCHAR>			tstring;
typedef std::basic_ostringstream<TCHAR>		tostringstream;
typedef std::vector<TCHAR>					tcharvector;
//	typedef std::ostream_iterator<TCHAR, TCHAR> tchartstream_iterator;

#include "SSMutex.h"

class CMGPattern
{
public:
	CMGPattern(TCHAR tchDelimiter = _T(' ')) : m_vector(), m_tchDelimiter(tchDelimiter)
	{
		AUTO_MUTEX(CMGPattern);
	}

	CMGPattern(const CMGPattern &rPattern)
	{
		AUTO_MUTEX(CMGPattern);

		*this = rPattern;
	}

	CMGPattern(LPCTSTR pszPattern, TCHAR tchDelimiter = NULL)
	{
		AUTO_MUTEX(CMGPattern);

		SetFromString(pszPattern, tchDelimiter);
		if(tchDelimiter)
			m_tchDelimiter = tchDelimiter;
	}

	virtual ~CMGPattern()
	{
		AUTO_MUTEX(CMGPattern);

		m_vector.clear();
	}

	CMGPattern &operator = (LPCTSTR pszPattern)
	{
		AUTO_MUTEX(CMGPattern);

		SetFromString(pszPattern);

		return *this;
	}

	CMGPattern &operator = (const CMGPattern &rPattern)
	{
		AUTO_MUTEX(CMGPattern);

		if(this == &rPattern) return *this;

		m_vector.clear();
		m_vector.reserve(rPattern.m_vector.size());
		std::copy( rPattern.m_vector.begin(), rPattern.m_vector.end(), std::back_inserter(this->m_vector) );
		
		m_tchDelimiter = rPattern.m_tchDelimiter;

		return *this;
	}

	operator tstring ()
	{
		AUTO_MUTEX(CMGPattern);

		return GetAsString().c_str();
	}

public:
	TCHAR SetDelimiter(TCHAR tchDelimiter)
	{
		AUTO_MUTEX(CMGPattern);

		return m_tchDelimiter = tchDelimiter;
	}

	TCHAR GetDelimiter()
	{
		AUTO_MUTEX(CMGPattern);

		return m_tchDelimiter;
	}

	size_t GetLength()
	{
		AUTO_MUTEX(CMGPattern);

		size_t nLen = m_vector.size();
		if(m_tchDelimiter)
			nLen *= 2;

		return nLen;
	}

	tstring GetAsString(TCHAR tchDelimiter = NULL)
	{
		AUTO_MUTEX(CMGPattern);

		tostringstream tss;

		TCHAR szDelimiter[2] = { NULL, NULL, };
		if(tchDelimiter)
			szDelimiter[0] = tchDelimiter;
		else if(m_tchDelimiter)
			szDelimiter[0] = m_tchDelimiter;

		tcharvector::iterator it = m_vector.begin();
		tcharvector::iterator itEnd = m_vector.end();

		while(it != itEnd)
		{
			 tss << (TCHAR)(*it) << szDelimiter;
			it++;
		}

		//	std::copy( m_vector.begin(), m_vector.end(), tchartstream_iterator( tss, szDelimiter ) );

		return tss.str().c_str();
	}

	int SetFromString(LPCTSTR pszPattern, TCHAR tchDelimiter = NULL)
	{
		AUTO_MUTEX(CMGPattern);

		if(tchDelimiter == NULL)
			tchDelimiter = m_tchDelimiter;

		m_vector.clear();
		int nLen = _tcslen(pszPattern);
		m_vector.reserve(nLen);
		for(int i = 0; i < nLen; )
		{
			m_vector.push_back(pszPattern[i++]);
			if(tchDelimiter)
			{
				if(pszPattern[i++] != tchDelimiter)
				{
					m_vector.clear();
					return -1;
				}
			}
		}

		// shrink a bloated vector
		tcharvector(m_vector).swap(m_vector);

		return m_vector.size();
	}

	int compare(LPCTSTR pszPattern, TCHAR tchDelimiter = NULL, BOOL bCaseSensitive = TRUE)
	{
		AUTO_MUTEX(CMGPattern);

		tcharvector::iterator it1 = m_vector.begin();
		tcharvector::iterator itEnd1 = m_vector.end();

		if(tchDelimiter == NULL)
			tchDelimiter = m_tchDelimiter;

		int iPattern = 0;
		while( it1 != itEnd1 && pszPattern[iPattern] )
		{

			TCHAR tchMark1 = (*it1);
			TCHAR tchMark2 = pszPattern[iPattern];

			if(!bCaseSensitive)
			{

#ifdef _UNICODE

				tchMark1 = (WCHAR)::towlower(tchMark1);
				tchMark2 = (WCHAR)::towlower(tchMark2);

#else	// #ifdef _UNICODE

				tchMark1 = (CHAR)::tolower(tchMark1);
				tchMark2 = (CHAR)::tolower(tchMark2);

#endif	// #ifdef _UNICODE

			}
			
			if(tchMark1 > tchMark2)
				return 1;
			else if(tchMark1 < tchMark2)
				return -1;
			
			it1++, iPattern++;

			if(tchDelimiter)
			{
				if(tchDelimiter != pszPattern[iPattern++])
				{
					TCHAR tchMark3 = tchDelimiter;
					TCHAR tchMark4 = pszPattern[iPattern - 1];
					
					if(!bCaseSensitive)
					{
						
#ifdef _UNICODE

						tchMark3 = (WCHAR)::towlower(tchMark3);
						tchMark4 = (WCHAR)::towlower(tchMark4);
						
#else	// #ifdef _UNICODE
						
						tchMark3 = (CHAR)::tolower(tchMark3);
						tchMark4 = (CHAR)::tolower(tchMark4);
						
#endif	// #ifdef _UNICODE

					}

					if(tchMark3 > tchMark4)
						return 1;
					else if(tchMark3 < tchMark2)
						return -1;
				}
			}
		}
		
		if(it1 == itEnd1 && NULL != pszPattern[iPattern] )
			return -1;
		
		if(NULL == pszPattern[iPattern] && it1 != itEnd1)
			return 1;
		
		return 0;
	}

	int compare(CMGPattern &rPattern, BOOL bCaseSensitive = TRUE)
	{
		AUTO_MUTEX(CMGPattern);
		
		tcharvector::iterator it1 = m_vector.begin();
		tcharvector::iterator itEnd1 = m_vector.end();

		tcharvector::iterator it2 = rPattern.m_vector.begin();
		tcharvector::iterator itEnd2 = rPattern.m_vector.end();

		while(it1 != itEnd1 && it2 != itEnd2)
		{

			TCHAR tchMark1 = (*it1);
			TCHAR tchMark2 = (*it2);

			if(!bCaseSensitive)
			{

#ifdef _UNICODE

				tchMark1 = (TCHAR)towlower(tchMark2);
				tchMark2 = (TCHAR)towlower(tchMark2);

#else	// #ifdef _UNICODE

				tchMark1 = (CHAR)tolower(tchMark1);
				tchMark2 = (CHAR)tolower(tchMark1);

#endif	// #ifdef _UNICODE

			}

			if(tchMark1 > tchMark2)
				return 1;
			else if(tchMark1 < tchMark2)
				return -1;

			it1++, it2++;
		}

		if(it1 == itEnd1 && it2 != itEnd2)
			return -1;

		if(it2 == itEnd2 && it1 != itEnd1)
			return 1;

		return 0;
	}

	BOOL equal(const CMGPattern &rPattern)
	{
		AUTO_MUTEX(CMGPattern);

		return std::equal(m_vector.begin(), m_vector.end(), rPattern.m_vector.begin());
	}

	BOOL empty()
	{
		AUTO_MUTEX(CMGPattern);

		return m_vector.empty();
	}

	void clear()
	{
		AUTO_MUTEX(CMGPattern);

		m_vector.clear();
	}

	void push_back(const TCHAR &tchMark)
	{
		AUTO_MUTEX(CMGPattern);

		m_vector.push_back(tchMark);
	}

	void pop_back()
	{
		AUTO_MUTEX(CMGPattern);

		m_vector.pop_back();
	}

	tcharvector::size_type size()
	{
		AUTO_MUTEX(CMGPattern);

		return m_vector.size();
	}

private:

	tcharvector m_vector;
	TCHAR m_tchDelimiter;
};

#endif	// #if !defined(MGPATTERN_H_INCLUDED)